﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace NGridDrawer.Draw
{
    /// <LastUpdate author="Blaise Braye" Date="15/06/2008 17:04"/>
    /// <author>Blaise Braye</author>
    /// <summary>
    /// useful helper for <see cref="DataGridView"/> components
    /// </summary>
    public static class DataGridViewExtension
    {
        /// <summary>
        /// </summary>
        /// <returns>affected Font to the cell</returns>
        /// <param name="cell">
        /// </param>
        public static Font Font(DataGridViewCell cell)
        {
            return (cell.HasStyle && cell.Style.Font != null)
                       ?
                           cell.Style.Font
                       : cell.InheritedStyle.Font;
        }


        /// <summary>
        /// Multiply the cell font with scale
        /// </summary>
        /// <param name="cell">
        /// </param>
        /// <param name="scale">percentage of font size</param>
        /// <returns>Scaled Font</returns>
        public static Font Font(DataGridViewCell cell, float scale)
        {
            Font font = Font(cell);

            if (scale != 1)
                font = new Font(font.FontFamily, (float) Math.Floor(font.Size*scale));

            return font;
        }

        /// <summary>
        /// Get the fore color of the cell
        /// </summary>
        /// <param name="cell">
        /// </param>
        /// <returns>ForeColor of the cell</returns>
        public static Color ForeColor(DataGridViewCell cell)
        {
            if (cell.HasStyle && cell.Style.ForeColor != Color.Empty) return cell.Style.ForeColor;

            return cell.InheritedStyle.ForeColor;
        }

        /// <summary>
        /// Get the BackColor of the cell
        /// </summary>
        /// <param name="cell">
        /// </param>
        /// <returns>BackColor of the cell</returns>
        public static Color BackColor(DataGridViewCell cell)
        {
            if (cell.HasStyle && cell.Style.BackColor != Color.Empty) return cell.Style.BackColor;

            return cell.InheritedStyle.BackColor;
        }

        /// <summary>
        /// Get the back color of the column headers of the <paramref name="gridView"/>
        /// </summary>
        /// <param name="gridView">
        /// </param>
        /// <returns>back color of the cell</returns>
        public static Color ColumnsHeaderBackColor(DataGridView gridView)
        {
            return (!gridView.ColumnHeadersDefaultCellStyle.BackColor.IsEmpty)
                       ? gridView.ColumnHeadersDefaultCellStyle.BackColor
                       : gridView.DefaultCellStyle.BackColor;
        }

        /// <summary>
        /// Get the fore color of the row
        /// </summary>
        /// <returns>fore color of the row</returns>
        /// <param name="band">
        /// </param>
        public static Color ForeColor(DataGridViewBand band)
        {
            if (band.HasDefaultCellStyle && band.DefaultCellStyle.ForeColor != Color.Empty)
                return band.DefaultCellStyle.ForeColor;

            return band.InheritedStyle.ForeColor;
        }

        /// <summary>
        /// Get the BackColor of the row
        /// </summary>
        /// <returns>BackColor of the row</returns>
        /// <param name="band">
        /// </param>
        public static Color BackColor(DataGridViewBand band)
        {
            if (band.Index%2 == 0 || band.DataGridView.AlternatingRowsDefaultCellStyle.BackColor.IsEmpty)
            {
                if (band.HasDefaultCellStyle && band.DefaultCellStyle.BackColor != Color.Empty)
                    return band.DefaultCellStyle.BackColor;

                return band.InheritedStyle.BackColor;
            }

            return band.DataGridView.AlternatingRowsDefaultCellStyle.BackColor;
        }

        /// <summary>
        /// Get text horizontal alignment in given cell
        /// </summary>
        /// <param name="cell">
        /// </param>
        /// <returns>text horizontal alignment in given cell</returns>
        public static StringAlignment HorizontalAlignment(DataGridViewCell cell)
        {
            DataGridViewContentAlignment alignement;

            if (cell.HasStyle && cell.Style.Alignment != DataGridViewContentAlignment.NotSet)
                alignement = cell.Style.Alignment;
            else alignement = cell.InheritedStyle.Alignment;

            // Check the CurrentCell alignment and apply it to the CellFormat
            if (alignement.ToString().Contains("Right"))
                return StringAlignment.Far;

            if (alignement.ToString().Contains("Center"))
                return StringAlignment.Center;

            return StringAlignment.Near;
        }


        /// <summary>
        /// Calculate the height of a <see cref="DataGridViewRow"/> in a drawing surface,
        /// it doesn't make calculation with hidden cells
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="row">
        /// </param>
        /// <returns>row height</returns>
        public static int RowHeight(Graphics graphic, DataGridViewRow row)
        {
            float max = float.MinValue;
            foreach (DataGridViewCell cell in row.Cells)
            {
                if (cell.Visible && cell.EditedFormattedValue != null)
                {
                    float cellHeight = graphic.MeasureString(
                        cell.EditedFormattedValue.ToString(),
                        Font(cell),
                        cell.Size.Width).Height;
                    if (cellHeight > max) max = cellHeight;
                }
            }
            return (int) Math.Ceiling(max);
        }

        /// <summary>
        /// Multiply row height with scale value
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="row">
        /// </param>
        /// <param name="scale">
        /// </param>
        /// <returns>Scaled height</returns>
        public static int RowHeight(Graphics graphic, DataGridViewRow row, float scale)
        {
            return (int) Math.Floor(RowHeight(graphic, row)*scale);
        }

        /// <summary>
        /// Calculate the height of a cell in a drawing surface
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="cell">
        /// </param>
        /// <returns>cell row height</returns>
        public static float RowHeight(Graphics graphic, DataGridViewCell cell)
        {
            return RowHeight(graphic, cell.OwningRow);
        }

        /// <summary>
        /// Multiply cell height with scale value
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="cell">
        /// </param>
        /// <param name="scale">
        /// </param>
        /// <returns>Scaled cell height</returns>
        public static float RowHeight(Graphics graphic, DataGridViewCell cell, float scale)
        {
            return RowHeight(graphic, cell)*scale;
        }

        /// <summary>
        /// Calculate the header height of a <see cref="DataGridView"/> in a drawing surface,
        /// it takes care only about visible columns
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="grid">
        /// </param>
        /// <returns><see cref="DataGridView"/> Columns Header Height</returns>
        public static int HeaderHeight(Graphics graphic, DataGridView grid)
        {
            float max = float.MinValue;
            foreach (DataGridViewColumn column in grid.Columns)
            {
                if (column.Visible)
                {
                    float headerHeight = graphic.MeasureString(
                        column.HeaderText,
                        Font(column.HeaderCell),
                        column.HeaderCell.Size.Width).Height;

                    if (headerHeight > max) max = headerHeight;
                }
            }

            return (int) Math.Ceiling(max);
        }


        /// <summary>
        /// Multiply <see cref="DataGridView"/> Columns Header Height with scale value 
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="grid">
        /// </param>
        /// <param name="scale">
        /// </param>
        /// <returns>Scaled <see cref="DataGridView"/> Columns Header Height</returns>
        public static int HeaderHeight(Graphics graphic, DataGridView grid, float scale)
        {
            return (int) Math.Floor(HeaderHeight(graphic, grid)*scale);
        }

        /// <summary>
        /// Calculate the width of a column in a drawing surface,
        /// it doesn't make calculation with hidden cells
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="column">
        /// </param>
        /// <returns>Column width</returns>
        public static int Width(Graphics graphic, DataGridViewColumn column)
        {
            float maxCellsWidth = float.MinValue;

            foreach (DataGridViewRow row in column.DataGridView.Rows)
            {
                if (row.Visible && row.Cells[column.Index].EditedFormattedValue != null)
                {
                    float cellWidth = graphic.MeasureString(
                        row.Cells[column.Index].EditedFormattedValue.ToString(),
                        Font(row.Cells[column.Index]),
                        row.Cells[column.Index].Size.Width).Width;

                    if (cellWidth > maxCellsWidth) maxCellsWidth = cellWidth;
                }
            }

            float headerWidth =
                graphic.MeasureString(
                    column.HeaderText,
                    Font(column.HeaderCell),
                    column.HeaderCell.Size.Width).Width;

            return (int) Math.Ceiling((maxCellsWidth > headerWidth) ? maxCellsWidth : headerWidth);
        }

        /// <summary>
        /// Multiply column width with scale value
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="column">
        /// </param>
        /// <param name="scale">
        /// </param>
        /// <returns>Scaled column width</returns>
        public static int Width(Graphics graphic, DataGridViewColumn column, float scale)
        {
            return (int) Math.Floor(Width(graphic, column)*scale);
        }

        public static int Width(Graphics graphic, DataGridViewCell cell)
        {
            return (int)Math.Floor(graphic.MeasureString(
                        cell.FormattedValue.ToString(),
                        DataGridViewExtension.Font(cell),
                        cell.Size.Width).Width);
        }

        /// <summary>
        /// Calculate the width of a <see cref="DataGridViewCell"/> in a drawing surface
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="cell">
        /// </param>
        /// <returns>Cell width</returns>
        public static float ColumnWidth(Graphics graphic, DataGridViewCell cell)
        {
            return Width(graphic, cell.OwningColumn);
        }

        /// <summary>
        /// Multiply cell width with scale value
        /// </summary>
        /// <param name="graphic">
        /// </param>
        /// <param name="cell">
        /// </param>
        /// <param name="scale">
        /// </param>
        /// <returns>Scaled cell width</returns>
        public static float ColumnWidth(Graphics graphic, DataGridViewCell cell, float scale)
        {
            return ColumnWidth(graphic, cell)*scale;
        }
    }
}